import {
  Body,
  Controller,
  Delete,
  Get,
  Inject,
  Logger,
  Param,
  ParseBoolPipe,
  Post,
  Put,
  Query,
  Res,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { UserService } from '../service/UserService';
import { R } from 'src/common/R';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { ClsService } from 'nestjs-cls';
import { UserDto } from '../dto/UserDto';
import PageResult from 'src/common/PageResult';
import UserQueryParam from '../param/UserQueryParam';
import TreeVo from 'src/common/TreeVo';
import { Response } from 'express';
import ServiceException from 'src/common/ServiceException';
import { FileInterceptor } from '@nestjs/platform-express';
import { AuthRoleDto } from '../dto/AuthRoleDto';
import { Constants } from 'src/common/Constants';
import { UserSession } from 'src/common/UserSession';
import { plainToInstance } from 'class-transformer';
import { Log } from 'src/common/decorator/log';
import BusinessType from 'src/common/enum/BusinessType';
import { PreAuthorize } from 'src/common/decorator/pre-authorize.decorator';

/*
 * @Author: jingfuu@163.com
 * @Date: 2024-10-06 15:11:36
 * @LastEditTime: 2024-10-12 16:25:22
 * @Description: 用户相关controller
 */
@ApiTags('用户接口')
@Controller('system/user')
export class UserController {
  private readonly logger = new Logger(UserController.name);

  @Inject()
  private userService: UserService;

  @Inject()
  private cls: ClsService;

  /**
   * 根据用户id查用户
   */
  @PreAuthorize('system:user:query')
  @ApiOperation({ summary: '根据用户id查用户' })
  @Get('/:id(\\d+)')
  async findUserById(@Param('id') id: number): Promise<any> {
    this.logger.log('query user by id start, id:' + id);
    return await this.userService.getDetail(id);
  }

  /**
   * 查新增用户需要的所有角色和职位
   * @returns
   */
  @ApiOperation({ summary: '查新增用户需要的所有角色和职位' })
  @Get('/')
  async findUserPostAndRole(): Promise<any> {
    return await this.userService.getPostAndRole();
  }

  /**
   * 分页查询用户列表
   */
  @PreAuthorize('system:user:query')
  @ApiOperation({ summary: '分页查询用户列表' })
  @Get('/list')
  async findUserList(@Query() param: UserQueryParam): Promise<R<UserDto>> {
    this.logger.log('query user list start, param:' + JSON.stringify(param));
    const result: PageResult<UserDto> = await this.userService.list(param);
    return R.page<UserDto>(result);
  }

  @PreAuthorize('system:user:export')
  @ApiOperation({ summary: '导出用户' })
  @Log({ title: '用户管理', businessType: BusinessType.EXPORT })
  @Post('/export')
  async exportUser(@Query() param: UserQueryParam, @Res() res: Response) {
    try {
      const buffer = await this.userService.export(param);
      res.set({
        'Content-Type': 'application/vnd.ms-excel',
        'Content-Disposition': 'attachment; filename=users.xlsx',
      });
      res.send(buffer);
    } catch (error) {
      this.logger.error('用户列表导出失败', error.stack);
      throw new ServiceException('用户列表导出失败');
    }
  }

  @ApiOperation({ summary: '导出新增用户excel模板' })
  @Post('importTemplate')
  async exportUserTemplate(@Res() res: Response) {
    try {
      const buffer = await this.userService.exportTemplate();
      res.set({
        'Content-Type': 'application/vnd.ms-excel',
        'Content-Disposition': 'attachment; filename=users.xlsx',
      });
      res.send(buffer);
    } catch (error) {
      this.logger.error('用户模板导出失败', error.stack);
      throw new ServiceException('用户模板导出失败');
    }
  }

  @Log({ title: '用户管理', businessType: BusinessType.IMPORT })
  @PreAuthorize('system:user:import')
  @ApiOperation({ summary: 'excel导入新增用户' })
  @Post('/importData')
  @UseInterceptors(FileInterceptor('file'))
  async importData(
    @UploadedFile() file: Express.Multer.File,
    @Query('updateSupport', ParseBoolPipe) updateSupport: boolean,
  ) {
    await this.userService.importUser(file, updateSupport);
    return R.ok();
  }

  /**
   * 获取部门树形结构
   *
   * 本函数通过调用userService中的deptTree方法来获取部门的树形结构数据，并返回给客户端
   * 主要用于展示部门之间的层级关系，以便于用户直观地浏览和操作部门数据
   *
   * @returns {Promise<R<TreeVo[]>>} 返回一个Promise，包含封装了部门树形结构数据的响应对象
   */
  @ApiOperation({ summary: '获取部门树形结构' })
  @Get('/deptTree')
  async deptTree(): Promise<R<TreeVo[]>> {
    return R.ok(await this.userService.deptTree());
  }

  /**
   * 删除用户接口，处理DELETE请求
   * @param id 用户ID，通过URL参数获取
   * @returns 返回一个Promise，表示异步操作的结果
   */
  @Log({ title: '用户管理', businessType: BusinessType.DELETE })
  @PreAuthorize('system:user:remove')
  @ApiOperation({ summary: '删除用户接口' })
  @Delete('/:id')
  async deleteUser(@Param('id') id: string): Promise<R<any>> {
    if (id.indexOf(',') > -1) {
      for (const item of id.split(',')) {
        await this.userService.deleteUser(Number.parseInt(item));
      }
    } else {
      await this.userService.deleteUser(Number.parseInt(id));
    }
    return R.ok();
  }

  /**
   * 更新用户信息
   * @param user 用户信息
   * @returns
   */
  @Log({ title: '用户管理', businessType: BusinessType.UPDATE })
  @PreAuthorize('system:user:edit')
  @ApiOperation({ summary: '修改用户接口' })
  @Put()
  async updateUser(@Body() user: UserDto): Promise<R<void>> {
    await this.userService.updateUser(user);
    return R.ok();
  }

  /**
   * 新增用户信息
   * @param user 用户信息
   * @returns
   */
  @Log({ title: '用户管理', businessType: BusinessType.INSERT })
  @PreAuthorize('system:user:add')
  @ApiOperation({ summary: '新增用户接口' })
  @Post()
  async addUser(@Body() user: UserDto): Promise<R<void>> {
    await this.userService.addUser(user);
    return R.ok();
  }

  @Log({ title: '用户管理', businessType: BusinessType.UPDATE })
  @ApiOperation({ summary: '用户状态切换' })
  @Put('changeStatus')
  async changeStatus(@Body() user: UserDto) {
    await this.userService.updateUser(user);
    return R.ok();
  }

  @Log({ title: '用户管理', businessType: BusinessType.UPDATE })
  @PreAuthorize('system:user:resetPwd')
  @ApiOperation({ summary: '重置密码' })
  @Put('resetPwd')
  async resetPwd(@Body() user: UserDto) {
    await this.userService.updateUser(user);
    return R.ok();
  }

  @ApiOperation({ summary: '查询分配角色' })
  @Get('authRole/:id(\\d+)')
  async queryAuthRole(@Param('id') id: number): Promise<any> {
    return await this.userService.authRole(id);
  }

  @Log({ title: '用户管理', businessType: BusinessType.OTHER })
  @ApiOperation({ summary: '分配角色' })
  @Put('authRole')
  async addAuthRole(@Query() data: AuthRoleDto) {
    const userDto = new UserDto();
    userDto.userId = data.userId;
    userDto.roleIds = data.roleIds;
    await this.userService.updateUser(userDto);
    return R.ok();
  }

  @ApiOperation({ summary: '获取用户个人信息' })
  @Get('/profile')
  async getProfile() {
    const userSession = this.cls.get<UserSession>(Constants.USER_SESSION);
    const userDto = userSession.user;
    let postGroup = '';
    let roleGroup = '';
    if (userDto.posts && userDto.posts.length > 0) {
      postGroup = userDto.posts.map((post) => post.postName).join(',');
    }
    if (userDto.roles && userDto.roles.length > 0) {
      roleGroup = userDto.roles.map((role) => role.roleName).join(',');
    }
    const sysUser = await this.userService.getById(userDto.userId);
    return {
      code: Constants.SUCCESS,
      data: plainToInstance(UserDto, sysUser),
      postGroup,
      roleGroup,
    };
  }

  @Log({ title: '个人信息', businessType: BusinessType.UPDATE })
  @ApiOperation({ summary: '修改个人信息' })
  @Put('/profile')
  async updateUserProfile(@Body() user: UserDto): Promise<R<any>> {
    const userSession = this.cls.get<UserSession>(Constants.USER_SESSION);
    user.userId = userSession.userId;
    this.userService.updateUser(user);
    return R.ok();
  }

  @Log({ title: '个人信息', businessType: BusinessType.UPDATE })
  @ApiOperation({ summary: '修改个人密码' })
  @Put('/profile/updatePwd')
  async updateUserPwd(
    @Query() data: { oldPassword: string; newPassword: string },
  ): Promise<R<any>> {
    const userSession = this.cls.get<UserSession>(Constants.USER_SESSION);
    await this.userService.updateUserPwd(
      userSession.userId,
      data.oldPassword,
      data.newPassword,
    );
    return R.ok();
  }
}
